package ink.tiptop.common;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * @author ink.tiptop.zjf
 * @Title: Ticket
 * @Package ink.tiptop.common.builder
 * @Description:    构建builder对象
 * @date 2020-07-24 14:32
 * @Use
 *  Order order = GenericBuilder.of(Order::new)
 *       .with(Order::setCode, "123232")
 *       .with(Order::addOffer, "满100减5")
 *       .with(Order::addFeature, "category", "shoe")
 *       .build();
 *
 *  LocalScanner build = GenericBuilder
 *         .of(() -> new LocalScanner(request.getPathLocal()))
 *         .with(LocalScanner::setFilePattern, "")
 *         .build();
 *
 *  LocalScanner build = GenericBuilder
 *           .of(() -> new LocalScanner(request.getPathLocal()))
 *           .with((a,b) -> {
 *               a.setLocalPath(b);
 *           }, "这个参数就是b")
 *           .build();
 */
public class GenericBuilder<T> {
    private final Supplier<T> instantiator;
    private List<Consumer<T>> instantiatorModifiers = new ArrayList<>();
    private List<Consumer<T>> keyValueModifiers = new ArrayList<>();
    public GenericBuilder(Supplier<T> instantiator) {
        this.instantiator = instantiator;
    }
    public static <T> GenericBuilder<T> of(Supplier<T> instantiator) {
        return new GenericBuilder<T>(instantiator);
    }

    /**
     * @param consumer  函数方法
     * @param value     函数入参
     * @param <U>
     * @return
     */
    public <U> GenericBuilder<T> with(BiConsumer<T, U> consumer, U value) {
        Consumer<T> c = instance -> consumer.accept(instance, value);
        instantiatorModifiers.add(c);
        return this;
    }

//    public <K, V> GenericBuilder<T> with(KeyValueConsumer<T, K, V> consumer, K key, V value) {
//        Consumer<T> c = instance -> consumer.accept(instance, key, value);
//        keyValueModifiers.add(c);
//        return this;
//    }

    public T build() {
        T value = instantiator.get();
        instantiatorModifiers.forEach(modifier -> modifier.accept(value));
        keyValueModifiers.forEach(keyValueModifier -> keyValueModifier.accept(value));
        instantiatorModifiers.clear();
        keyValueModifiers.clear();
        return value;
    }
}
